class Event < ActiveRecord::Base
  has_event_calendar

  DEFAULT_AM_OFFSET =  8.hours + 30.minutes
  DEFAULT_PM_OFFSET = 12.hours
  DEFAULT_END_SHIFT =  8.hours + 8.hours  #start at 8. work 8

  #Event operations
  CREATE  = 1
  APPROVE = 2
  EDIT    = 3
  DELETE  = 4

  #DURATION of events
  AM        = 1
  PM        = 2
  FULL_DAY  = 3
  MULTI_DAY = 4

  DURATIONS      = [ AM,         PM,         FULL_DAY,               MULTI_DAY ]
  DURATION_NAMES = { AM => "AM", PM => "PM", FULL_DAY => "Full Day", MULTI_DAY => "Multi Day"}
  
  #TYPES of events
  REGULAR      = 1
  VACATION     = 2
  PC_HOLIDAY   = 3
  SITE_HOLIDAY = 4
  PRIMARY      = 5
  SECONDARY    = 6

  TYPES      = [ REGULAR, VACATION, PC_HOLIDAY, SITE_HOLIDAY, PRIMARY, SECONDARY ]
  TYPE_NAMES = { REGULAR    => "Reg. Event",    VACATION     => "Vacation", 
                 PC_HOLIDAY => "PC Holiday",    SITE_HOLIDAY => "Site Holiday",
                 PRIMARY    => "Primary Shift", SECONDARY    => "Secondary Shift" }

  belongs_to :creator,  :class_name => 'User', :foreign_key => 'creator_id' 
  belongs_to :approver, :class_name => 'User', :foreign_key => 'approver_id'
  belongs_to :owner,    :class_name => 'User', :foreign_key => 'owner_id'

  validates_presence_of  :name,
                         :creator_id,
                         :event_type,
                         :begin_date,
                         :owner_id

  validates_presence_of  :end_date, :if => Proc.new {|event| event.event_type == MULTI_DAY}
  validates_inclusion_of :duration_type, :in => (DURATIONS.min)..(DURATIONS.max) 
  validates_inclusion_of :event_type,    :in => (TYPES.min)..(TYPES.max) 

  before_validation :correct_end_date_by_duration_type
  before_save       :enforce_correct_duration_type

  def link
    case event_type
    when SITE_HOLIDAY
      %(<a href="/events/#{id}/" title="#{name}">#{name}</a>)
    else
       %(<a href="/events/#{id}" title="#{name}">#{owner.username} - #{name}</a>)
    end
  end

  def correct_end_date_by_duration_type
    if end_date.nil? || begin_date.nil?
      return
    end

    if duration_type != Event::MULTI_DAY
      self.end_date = begin_date
    end
    true
  end

  def enforce_correct_duration_type
    if duration_type == Event::MULTI_DAY && duration == 1
      write_attribute(:duration_type, Event::FULL_DAY)
    end
  end

  def color
    if event_type == SITE_HOLIDAY
      return "#ffaa00"
    elsif event_type == PRIMARY
      return "#05CCCC"
    elsif event_type == SECONDARY
      return "#05B3B3"
    elsif !approved
      return "#D60000"
    elsif event_type == VACATION || event_type == PC_HOLIDAY
      return "#69CC05"
    else
      return "#669966"
    end
  end

  def duration
    if [Event::AM, Event::PM].include?(duration_type)
      begin_date.saturday? || begin_date.sunday? ? 0.5 : 0
    elsif duration_type == Event::MULTI_DAY 
      return (end_date - begin_date).to_i + 1
    else
      begin_date.saturday? || begin_date.sunday? ? 0 : 0.5
    end
  end

  def validate
    if start_at.nil? || end_at.nil? || begin_date.nil? || end_date.nil?
      return
    end
    if start_at > end_at || begin_date > end_date
      errors.add("", "Event cannot end before it starts")
    end
  end

  def begin_date=(value)
    write_attribute(:begin_date, value)
    update_start_at
  end

  def end_date=(value)
    write_attribute(:end_date, value)
    update_end_at
  end

  def type=(value)
    write_attribute(:type, value)
    update_start_at if !start_at.nil?
    update_end_at   if !end_at.nil?
  end

  def update_start_at
    am_offset = nil
    case event_type
    when PM
      am_offset = (owner.nil? || owner.beginning_of_shift.nil?) ? DEFAULT_AM_OFFSET : owner.end_of_shift / 2
    when DateTime
    else #handles am, full_day, multi_day, and undefined
      am_offset = (owner.nil? || owner.beginning_of_shift.nil?) ? DEFAULT_AM_OFFSET : owner.beginning_of_shift
    end

    self.start_at = begin_date.to_datetime.plus_with_duration(am_offset)
  end

  def update_end_at
    pm_offself = nil
    case event_type
    when AM
      pm_offset = (owner.nil? || owner.beginning_of_shift.nil?) ? DEFAULT_PM_OFFSET : owner.end_of_shift / 2
    else # PM, MULTI_DAY, FULL_DAY 
      pm_offset = (owner.nil? || owner.beginning_of_shift.nil?) ? DEFAULT_END_SHIFT : owner.end_of_shift 
    end
    self.end_at = end_date.to_datetime.plus_with_duration(pm_offset)
  end

  def today?
    return begin_date <= Date.today && end_date >= Date.today
  end

  def remaining_days
    if duration_type == Event::MULTI_DAY && today?
      return end_date - Date.today
    elsif today?
      return duration
    else
      return 0
    end
  end

  def display?
    true
  end
end
